; *******************************************************************
; * exp4_3.asm
; * LLP STUDIO Chen Zhepeng
; * V1.0
; * 2023-11-18
; * 按键外部中断
; * 显示中断次数：KEY1左边数码管数字减小，KEY2右边数码管数字减小
; * 每次中断使LED-0603闪烁3次熄灭
; *******************************************************************

P4         DATA 0C0H
P6         DATA 0E8H
P4M1       DATA 0B3H
P4M0       DATA 0B4H
P6M1       DATA 0CBH
P6M0       DATA 0CCH
HC595_SI   BIT  P4.4  ; 74HC595串行输入端
HC595_SCK  BIT  P4.2  ; 74HC595移位时钟输入
HC595_RCK  BIT  P4.3  ; 74HC595锁存时钟输入
DISP_BLACK EQU  10H   ; 对应段码表0FFH（全黑）
NIXIE8     DATA 30H   ; 显示缓冲30H ~ 37H
disp_index DATA 38H   ; 显示位索引
; 测试用的计数变量
int_cnt    DATA 39H

ORG 0000H
LJMP Main
ORG 0003H
LJMP Int0Sub
ORG 0013H
LJMP Int1Sub
ORG 0100H
Main:
; P4口推挽，其他准双向
MOV P4M1, #00H
MOV P4M0, #01H
; 设置P6口为推挽输出
MOV P6M1, #00H
MOV P6M0, #0FFH
MOV SP, #80H
MOV disp_index, #0  ; 消隐
MOV R0, #NIXIE8  ; 灭灯
MOV R2, #8  ; 8个数码管，执行8次
SETB P4.0  ; 关闭8个LED
ClearLoop:
MOV @R0, #DISP_BLACK
INC R0
DJNZ R2, ClearLoop
CLR IE1
CLR IE0
SETB EX1
SETB EX0
; 下降沿中断
SETB IT0
SETB IT1
SETB EA
MainLoop:
LCALL DELAY2MS
LCALL ScanDisp
LJMP MainLoop

PosTable:
DB 80H, 40H, 20H, 10H, 08H, 04H, 02H, 01H
SegTable:
DB 0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8
DB 0X80, 0X90, 0X88, 0X83, 0XC6, 0XA1, 0X86, 0X8E
DB 0FFH  ; 全黑

; * @brief       向74HC595D发送一个字节
; * @param       ACC: 要发送的字节数据（存放在累加器中）
; * @retval      无
Hc595SendByte:
PUSH 02H
MOV R2, #8
Hc595SendLoop:
RLC A
MOV HC595_SI, C
SETB HC595_SCK
CLR HC595_SCK
DJNZ R2, Hc595SendLoop
POP 02H
RET

; * @brief       数码管动态显示
; * @param       无
; * @retval      无
ScanDisp:
PUSH DPH
PUSH DPL
PUSH 00H
MOV A, #00H
LCALL Hc595SendByte  ; 输出点阵位码，关闭点阵
MOV DPTR, #PosTable
;MOV A, R0
MOV A, disp_index
MOVC A, @A + DPTR
LCALL Hc595SendByte  ; 输出位码
CLR HC595_RCK
NOP
SETB HC595_RCK  ; 上升沿并行锁存到输出端
NOP
CLR HC595_RCK  ; 锁存输出数据
MOV DPTR, #SegTable
;MOV A, R1
MOV A, disp_index
ADD A, #NIXIE8  ; 根据disp_index指示的第几个数码管，
MOV R0, A  ; 定位要显示的数码管
MOV A, @R0
MOVC A, @A + DPTR
MOV P6, A  ; 输出段码
INC disp_index
MOV A, disp_index
ANL A, #0F8H
JZ QuitScanDisp  ; disp_index == 0 ~ 7跳转
; if (disp_index >= 8)
; {
MOV disp_index, #0  ; 8位结束回0
; }
MOV A, int_cnt
MOV B, #100
DIV AB
MOV NIXIE8 + 0, A
MOV A, #10
XCH A, B
DIV AB
MOV NIXIE8 + 1, A
MOV NIXIE8 + 2, B
MOV NIXIE8 + 3, #DISP_BLACK
MOV NIXIE8 + 4, #DISP_BLACK
MOV NIXIE8 + 5, #DISP_BLACK
MOV NIXIE8 + 6, #DISP_BLACK
MOV NIXIE8 + 7, #DISP_BLACK
; else
; {
QuitScanDisp:
POP 00H  ; R0出栈
POP DPL
POP DPH
RET
; }

; * @brief       INT0中断子程序
; * @param       无
; * @retval      无
Int0Sub:
LCALL DELAY20MS
LCALL ScanDisp
JNB P3.2, Int0Sub
LCALL DELAY20MS
DEC int_cnt
MOV R7, #6
MOV R6, #255
Int0Loop:
CPL P4.1
Int0ScanDisp:
LCALL ScanDisp
LCALL DELAY2MS
DJNZ R6, Int0ScanDisp
DJNZ R7, Int0Loop
CLR P4.1
RETI

; * @brief       INT1中断子程序
; * @param       无
; * @retval      无
Int1Sub:
LCALL DELAY20MS
LCALL ScanDisp
JNB P3.3, Int1Sub
LCALL DELAY20MS
DEC int_cnt
MOV R7, #6
MOV R6, #255
Int1Loop:
CPL P4.1
Int1ScanDisp:
LCALL ScanDisp
LCALL DELAY2MS
DJNZ R6, Int1ScanDisp
DJNZ R7, Int1Loop
CLR P4.1
RETI

; * @brief       2 ms延时（由STC-ISP生成）
; * @param       无
; * @retval      无
DELAY2MS:			;@24.000MHz
	NOP
	PUSH	30H
	PUSH	31H
	MOV		30H,#63
	MOV		31H,#82
NEXT:
	DJNZ	31H,NEXT
	DJNZ	30H,NEXT
	POP		31H
	POP		30H
	RET

; * @brief       20 ms延时（由STC-ISP生成）
; * @param       无
; * @retval      无
DELAY20MS:			;@24.000MHz
	NOP
	PUSH	30H
	PUSH	31H
	PUSH	32H
	MOV		30H,#3
	MOV		31H,#112
	MOV		32H,#89
DelayLoop:
	DJNZ	32H,DelayLoop
	DJNZ	31H,DelayLoop
	DJNZ	30H,DelayLoop
	POP		32H
	POP		31H
	POP		30H
	RET

END